#include "preHeader.h"
#include "Session/PlayerPacketHandler.h"
#include "Session/DBPServerMgr.h"
#include "Object/Player.h"

void Player::DoGetMailAttachment(INetStream& data)
{
	std::vector<InstMailAttachment> mailAttachments;
	while (!data.IsReadableEmpty()) {
		mailAttachments.push_back({});
		LoadFromINetStream(mailAttachments.back(), data);
	}

	NetPacket pack2Player(SMSG_MAIL);
	pack2Player << (s32)MAIL_RQST_TYPE::GET_ATTACHMENT;
	NetPacket rpcReqPck(CDBP_PLAYER_GET_MAIL_ATTACHMENT);
	rpcReqPck << GetGuidLow();

	bool isOk = false;
	GErrorCode errCode = CommonSuccess;
	for (const auto& mailAttachment : mailAttachments) {
		auto mailCheques = ConvertMailAttachmentCheques(mailAttachment);
		auto errCheque = CanGetMailAttachmentCheques(mailCheques);
		if (errCheque != CommonSuccess) {
			errCode = errCheque;
			continue;
		}
		auto mailItems = ConvertMailAttachmentItems(mailAttachment);
		auto errItem = CanGetMailAttachmentItems(mailItems);
		if (errItem != CommonSuccess) {
			errCode = errItem;
			continue;
		}
		DoGetMailAttachmentCheques(mailCheques);
		DoGetMailAttachmentItems(mailItems);
		pack2Player << mailAttachment.mailID;
		rpcReqPck << mailAttachment.mailID;
		isOk = true;
	}

	if (isOk) {
		DBPSession(GetGsId()).RPCInvoke(rpcReqPck);
	} else {
		SendError(errCode);
	}
	SendPacket(pack2Player);
}

void Player::DoGetMailAttachmentCheques(const std::vector<MailCheque>& mailCheques)
{
	for (const auto& mailCheque : mailCheques) {
		GainCheque(ChequeType(
			mailCheque.chequeType), mailCheque.chequeValue, CFT_MAIL, {});
	}
}

void Player::DoGetMailAttachmentItems(const std::pair<
	std::vector<const ItemPrototype*>, std::vector<inst_item_prop>>& mailItems)
{
	m_pItemStorage->CreateAddItems(mailItems.first.data(), mailItems.second.data(),
		mailItems.second.size(), IFT_MAIL, {});
}

GErrorCode Player::CanGetMailAttachmentCheques(
	const std::vector<MailCheque>& mailCheques) const
{
	return CommonSuccess;
}

GErrorCode Player::CanGetMailAttachmentItems(const std::pair<
	std::vector<const ItemPrototype*>, std::vector<inst_item_prop>>& mailItems) const
{
	auto lackSlotCnt = m_pItemStorage->GetFillItemsLackSlotCount(
		mailItems.first.data(), mailItems.second.data(), mailItems.second.size());
	if (lackSlotCnt > 0) {
		return ErrItemStorageSlotNotEnough;
	}
	return CommonSuccess;
}

std::vector<MailCheque>
Player::ConvertMailAttachmentCheques(const InstMailAttachment& mailAttachment)
{
	std::vector<MailCheque> mailCheques;
	mailCheques.reserve(mailAttachment.mailCheques.size());
	for (const auto& mailChequeStr : mailAttachment.mailCheques) {
		TextUnpacker unpacker(mailChequeStr.c_str());
		MailCheque mailCheque;
		unpacker >> mailCheque.chequeType >> mailCheque.chequeValue;
		mailCheques.push_back(std::move(mailCheque));
	}
	return mailCheques;
}

std::pair<std::vector<const ItemPrototype*>, std::vector<inst_item_prop>>
Player::ConvertMailAttachmentItems(const InstMailAttachment& mailAttachment)
{
	std::vector<const ItemPrototype*> itemProtos;
	std::vector<inst_item_prop> itemProps;
	itemProtos.reserve(mailAttachment.mailItems.size());
	itemProps.reserve(mailAttachment.mailItems.size());
	for (const auto& itemPropStr : mailAttachment.mailItems) {
		TextUnpacker unpacker(itemPropStr.c_str());
		inst_item_prop itemProp;
		itemProp.Load(unpacker);
		auto pItemProto = GetDBEntry<ItemPrototype>(itemProp.itemTypeID);
		if (pItemProto != NULL) {
			itemProtos.push_back(pItemProto);
			itemProps.push_back(std::move(itemProp));
		} else {
			WLOG("Invalid mail item %u.", itemProp.itemTypeID);
		}
	}
	return std::make_pair(std::move(itemProtos), std::move(itemProps));
}

GErrorCode Player::HandleGetMailCountAll(INetPacket& pck)
{
	NetPacket rpcReqPck(CDBP_GET_PLAYER_MAIL_COUNT);
	rpcReqPck << GetGuidLow();
	DBPSession(GetGsId()).RPCInvoke(rpcReqPck, [=](INetStream& pck, int32 err, bool) {
		if (err == RPCErrorNone) {
			NetPacket pack(SMSG_MAIL);
			pack << (s32)MAIL_RQST_TYPE::COUNT_ALL;
			pack.Append(pck.GetReadableBuffer(), pck.GetReadableSize());
			SendPacket(pack);
		}
	}, this);
	return CommonSuccess;
}

GErrorCode Player::HandleGetMailListSomes(INetPacket& pck)
{
	NetPacket rpcReqPck(CDBP_GET_PLAYER_MAIL_LIST);
	rpcReqPck << GetGuidLow();
	DBPSession(GetGsId()).RPCInvoke(rpcReqPck, [=](INetStream& pck, int32 err, bool) {
		if (err == RPCErrorNone) {
			NetPacket pack(SMSG_MAIL);
			pack << (s32)MAIL_RQST_TYPE::LIST_SOMES;
			pack.Append(pck.GetReadableBuffer(), pck.GetReadableSize());
			SendPacket(pack);
		}
	}, this);
	return CommonSuccess;
}

GErrorCode Player::HandleGetMailAttachment(INetPacket& pck)
{
	if (pck.IsReadableEmpty()) {
		return InvalidRequest;
	}
	if (IsMailExporting()) {
		return ErrMailExporting;
	}
	NetPacket rpcReqPck(CDBP_GET_PLAYER_MAIL_ATTACHMENT);
	rpcReqPck << GetGuidLow();
	while (!pck.IsReadableEmpty()) {
		rpcReqPck << pck.Read<uint32>();
	}
	DBPSession(GetGsId()).RPCInvoke(rpcReqPck, [=](INetStream& pck, int32 err, bool) {
		SetMailExporting(false);
		if (err == RPCErrorNone) {
			DoGetMailAttachment(pck);
		}
	}, this);
	SetMailExporting(true);
	return CommonSuccess;
}

GErrorCode Player::HandleViewMailDetail(INetPacket& pck)
{
	if (pck.IsReadableEmpty()) {
		return InvalidRequest;
	}
	NetPacket rpcReqPck(CDBP_PLAYER_VIEW_MAIL_DETAIL);
	rpcReqPck << GetGuidLow();
	while (!pck.IsReadableEmpty()) {
		rpcReqPck << pck.Read<uint32>();
	}
	DBPSession(GetGsId()).RPCInvoke(rpcReqPck);
	return CommonSuccess;
}

GErrorCode Player::HandleWriteMail(INetPacket& pck)
{
	return InvalidRequest;
}

GErrorCode Player::HandleDeleteMail(INetPacket& pck)
{
	if (pck.IsReadableEmpty()) {
		return InvalidRequest;
	}
	NetPacket rpcReqPck(CDBP_PLAYER_DELETE_MAIL);
	rpcReqPck << GetGuidLow();
	while (!pck.IsReadableEmpty()) {
		rpcReqPck << pck.Read<uint32>();
	}
	DBPSession(GetGsId()).RPCInvoke(rpcReqPck, [=](INetStream& pck, int32 err, bool) {
		if (err == RPCErrorNone) {
			NetPacket pack(SMSG_MAIL);
			pack << (s32)MAIL_RQST_TYPE::DELETE_ORDER;
			SendPacket(pack);
		}
	}, this);
	return CommonSuccess;
}

GErrorCode Player::HandleMailRequest(INetPacket& pck)
{
	int32 rqstType;
	pck >> rqstType;
	switch (MAIL_RQST_TYPE(rqstType)) {
	case MAIL_RQST_TYPE::COUNT_ALL:
		return HandleGetMailCountAll(pck);
	case MAIL_RQST_TYPE::LIST_SOMES:
		return HandleGetMailListSomes(pck);
	case MAIL_RQST_TYPE::GET_ATTACHMENT:
		return HandleGetMailAttachment(pck);
	case MAIL_RQST_TYPE::VIEW_DETAIL:
		return HandleViewMailDetail(pck);
	case MAIL_RQST_TYPE::WRITE_ORDER:
		return HandleWriteMail(pck);
	case MAIL_RQST_TYPE::DELETE_ORDER:
		return HandleDeleteMail(pck);
	default:
		return InvalidRequest;
	}
}

int PlayerPacketHandler::HandleMail(Player *pPlayer, INetPacket &pck)
{
	GErrorCode err = pPlayer->HandleMailRequest(pck);
	if (err != CommonSuccess) {
		pPlayer->SendError(err);
	}
	return SessionHandleSuccess;
}
